﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

using VietNamKey.Properties;

namespace VietNamKey
{
    public partial class frmMain
    {
    	private VNWord VN = new VNWord();
        private bool isDeleting = false;
        private bool control = false;
        private bool shift = false;
        private bool alt = false;
        private bool another = false;
        private bool IsVNMode = true;
        private bool IsCanRestore = true;
        /// <summary>
        /// Lưu lại văn bản mà người dùng gõ, lưu theo đúng bảng mã người dùng sử dụng
        /// </summary>
        private string Cache = "";
        /// <summary>
        /// Lưu lại ký tự người dùng gõ (văn bảng gốc nếu ở chế độ EN)
        /// </summary>        
        private string ScoureCache = "";
    	
        private void ResetCache()
        {
        	Cache = ScoureCache = "";
        	VN.Reset();
        }
        
    	private void MyMouseActivity(object sender, MouseEventArgs e)
    	{
//    		if(e.Button != MouseButtons.None)
//    			ResetCache();
    	}
    	
        private void MyKeyDown(object sender, KeyEventArgs e)
        {
        	//if(Global.KeySettings.EnabledLogView) txtKeyDown.Text = e.KeyData.ToString();
        	switch(e.KeyData)
        	{
    			case Keys.LControlKey: case Keys.RControlKey: control = true; break;
        		case Keys.LShiftKey: case Keys.RShiftKey: shift = true; break;
        		case Keys.LMenu: case Keys.RMenu: alt = true; break;
        		default: another = true; break;
        	}
            
        	if ((new List<Keys>(){Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp, Keys.Left, Keys.Right, Keys.Up, Keys.Down}).Contains(e.KeyData)
        		||(control | alt))
                ResetCache();
            
        }

        private void MyKeyPress(object sender, KeyPressEventArgs e)
        {    
        	if(isDeleting || control || alt || (!IsVNMode && !Global.KeySettings.UseShorthandInEn)) return;
        	if(e.KeyChar != '\b') //backspace
        	{ 
        		Cache += e.KeyChar;
        		ScoureCache += e.KeyChar;
        		if(ScoureCache.Length > 100)
        		{ // bộ đệm chỉ lưu 100 ký tự => sửa lại lớn hơn cũng được
        			Cache.Substring(10);
        			ScoureCache.Substring(10);
        		}
        		//if(Global.KeySettings.EnabledLogView) txtCache.Text = Cache;
        	} 
        	else
        	{ 
        		// tắt khôi phục từ nếu ký tự cần xoá là một ký tự tiếng việt có dấu
        		// vì khi xoá sẽ gây sai lệch cho scoureCache do 
        		if(Cache.Length > 0) // UNDONE: Vẫn còn lệch một số chỗ đo set IsCanRestore chưa chuẩn
        		{
        			string str = ToUni(Cache.Substring(Cache.Length - 1));
        			string tmp = Cache.Substring(0, Cache.Length - 1);
	        		if(IsCanRestore && Cache.Length > 0 && Encodings.ConvertToUnsign(str) != str)
	        		{
	        			IsCanRestore = tmp.Length > 0 ? CheckSymbol(tmp[tmp.Length - 1]) : true;
	        			ScoureCache = "";
	        		}
	        		if(tmp.Length > 0 && !CheckSymbol(Cache[Cache.Length - 1]) && CheckSymbol(Cache[Cache.Length - 2]))
	        		{
	        			string Word = GetWord(tmp);
	        			System.Diagnostics.Debug.Print("new = '{0}'", Word);
	        			VN = new VNWord(Word + '\b');
	        			Cache = tmp;
	        		}
        		  	else
        		  	{
	        			VN.RemoveChar();
	        			Cache = tmp;
	        			if(IsVNMode && Cache.Length > 0 && VN.FinalConsonant.Length == 0 && !Global.KeySettings.UseNewStyle) 
			        	{//trường hợp bỏ dấu kiểu cũ hoàn -> hòa thay lại vị trí dấu nguyên âm
			        		string sWord = GetWord(ToUni(Cache));
				        	if(sWord.Length > 1 && sWord.Length < 8) //nghienge
								SendOut(sWord, VN.Value, e, 2, "");
			        	}
        		  	}
	        		if(ScoureCache.Length > 0)
	        			if(Cache.Length > 0 && " \r\t".Contains(Cache.Substring(Cache.Length - 1, 1))) //khi xoá tới dấu cách => xoá ở ScoureCache luôn
	        				ScoureCache = ScoureCache.Substring(0,ScoureCache.LastIndexOfAny(new[]{' ', '\r', '\t'}) + 1);
		    			else
		        			ScoureCache = ScoureCache.Substring(0, ScoureCache.Length - 1);
        		}
        		else ResetCache();
        		//if(Global.KeySettings.EnabledLogView) txtCache.Text = Cache;
        		return; //vì là dấu xoá nên thoát luôn không bỏ dấu hay làm cái khác
        	}
        	if(!CheckSymbol(e.KeyChar)) // là một ký tự đặt biệt
        	{ // kết thúc từ => kiểm tra gõ tắt và kiểm tra chính tả để trả về nguyên gốc
        		int lif = ScoureCache.Substring(0, ScoureCache.Length - 1).LastIndexOfAny(new[]{' ', '\t', '\r'});
        		string ScoureWord = lif != -1 ? ScoureCache.Substring(lif + 1) : ScoureCache;
        		ScoureWord = ScoureWord.Substring(0, ScoureWord.Length - 1);
        		if(Global.KeySettings.UseShorthand && (Global.KeySettings.UseShorthandInEn || IsVNMode))
	        		for (int i = 0; i < Global.KeySettings.ShorthandList.Count; i++)
		            { // tra bảng gõ tắt và xuất ra tương ứng, không xuất dấu cách trắng
        				if (Global.KeySettings.ShorthandList[i][0].ToLower() == ScoureWord.ToLower())
		                {
		                	e.Handled = true;
		                	isDeleting = true;
		                	SendBack(ScoureWord.Length);
		                    if (Global.KeySettings.ShorthandList[i][0] == ScoureWord)
		                    	SendText(Encodings.ConvertFromUnicode(Global.KeySettings.ShorthandList[i][1] + e.KeyChar, Encodings.List[Global.KeySettings.Encoding].Value), true);
		                    else if (Global.KeySettings.ShorthandList[i][0].ToUpper() == ScoureWord)
		                        SendText(Encodings.ConvertFromUnicode(Global.KeySettings.ShorthandList[i][1].ToUpper() + e.KeyChar, Encodings.List[Global.KeySettings.Encoding].Value), true);
		                    else // lower
		                        SendText(Encodings.ConvertFromUnicode(Global.KeySettings.ShorthandList[i][1].ToLower() + e.KeyChar, Encodings.List[Global.KeySettings.Encoding].Value), true);
		                    isDeleting = false;
		                    ResetCache();
		                    return;
		                }
		            }
        		if(!IsVNMode) return;
    			//System.Diagnostics.Debug.Print("cache = '{0}' scache = '{1}'", Cache, ScoureCache);
    			// hỗ trợ gõ tắt phụ âm
    			if(Cache.Length > 2)
    			{
    				string strCache = ToUni(Cache.Substring(0, Cache.Length - 1));
	    			string sWord = CheckSymbol(strCache[strCache.Length - 1]) ? GetWord(strCache): "";

	    			if(!VN.Error && VN.FinalConsonant.Length == 1 && sWord.Length > 0 && (Global.KeySettings.AutoFC || Global.KeySettings.AutoAcute))
	    			{ // hỗ trợ gõ tắt phụ âm cuối 
	    				VN.ShorthandFC();
	    				SendOut(sWord, VN.Value, e, 1, e.KeyChar.ToString());
	    			}
	        		if(Global.KeySettings.UseRestoreEN && IsCanRestore)
	        		{// kiểm chính tả tiếng việt
	        			//System.Diagnostics.Debug.Print("W2 = '{0}' {1}", Word, Encodings.ConvertToUnsign(Word));
	        			// nếu có dấu, độ dài bé hơn hoặc bằng 7 và không là từ tiếng việt thì chuyển sang dạng nguồn
	        			if(sWord.Length > 7 ||(sWord.Length > 1 && sWord != Encodings.ConvertToUnsign(sWord) && !VN.isVNWord())) 
		        		{// từ tiếng việt dài nhất là Nghiêng có 7 ký tự 
		        			e.Handled = true;
		                	isDeleting = true;
		                	SendBack(sWord.Length);
		                	SendText(ScoureWord + e.KeyChar, true);
		                	Cache = Cache.Substring(0, Cache.Length - sWord.Length - 1) + ScoureWord;
		                	//ScoureCache = ScoureCache.Substring(0, ScoureCache.Length - Word.Length) + ScoureWord + " ";
		                	isDeleting = false;
		        		}
	        		}
    			}
        		// bật lại phục hồi từ khi bắt đầu từ mới
        		IsCanRestore = true;
        		if(IsVNMode) VN.Reset();
	        	System.Diagnostics.Debug.Print("cache1 = '{0}'", Cache);
        		return;
        	}// không phải dấu xoá và dấu , tiếng hành kiểm tra coi có phải ký tự bỏ dấu ko
        	else if(IsVNMode)
        	{
        		string sWord = GetWord(ToUni(Cache));
	        	if(sWord.Length < 1 || sWord.Length > 8) return; //nghienge
	        	VN.AddChar(e.KeyChar);
	        	SendOut(sWord, VN.Value, e, 0, "");
	        	System.Diagnostics.Debug.Print("cache2 = '{0}'", Cache);	        	
        	}
        }
        
        private void SendOut(string sWord, string strVN, KeyPressEventArgs e, int BackBonus, string strBonus)
        {
        	System.Diagnostics.Debug.Print("Send out: word = '{0}' strVN = '{1}'", sWord, strVN);
        	if(!string.IsNullOrEmpty(strVN) && !sWord.StartsWith(strVN))
    		{
    			e.Handled = true;
    			int BackLength = GetBackLength(sWord, strVN);
				strVN = FromUni(strVN.Substring(sWord.Length - BackLength));
				if(Encodings.List[Global.KeySettings.Encoding] != Encodings.Unicode)
				{ // nếu không phải là chế độ unicode thì tính toán lại số ký tự cần xoá
					string str = sWord.Substring(0, sWord.Length - 1);
					BackLength -= str.Length;
					str = Encodings.ConvertFromUnicode(str, Encodings.List[Global.KeySettings.Encoding].Value);
					BackLength += str.Length;
				}
				Cache = Cache.Substring(0, Cache.Length - BackLength - strBonus.Length);
				isDeleting = true;
				SendBack(BackLength - 1 + BackBonus);
				SendText(strVN + strBonus, false);
				isDeleting = false;
				Cache += strVN + strBonus;
				//if(Global.KeySettings.EnabledLogView) txtCache.Text = Cache;
    		}
        }
        
        //Tính xem cần xoá số lượng ký tự ít nhất là bao nhiêu để thay word thành strVN 
        private int GetBackLength(string sWord, string strVN)
        {
        	int BackLength = sWord.Length;
        	for(int i = 0; i < Math.Min(strVN.Length, sWord.Length); i++)
				if(sWord[i] == strVN[i]) BackLength--;
				else break;
			return BackLength;
        }
        // Lấy từ, duyệt từ sau ra trước cho tới khi gặp ký tự đặt biệt
        private string GetWord(string sText)
        {
        	string sWord = "";
    		for(int i = 2; i <= sText.Length; i++)
        	{
    			if(CheckSymbol(sText[sText.Length - i])) 
    			   sWord = sText[sText.Length - i] + sWord;
			   	else break;
        	}
    		sWord += sText[sText.Length - 1];
    		return sWord;
        }
        // kiểm tra nó có phải là ký tự đặt biệt ko true nếu ko phải
		private bool CheckSymbol(char uc)
		{
			return uc != ' ' && ((uc >= 'a' && uc <= 'z')||(uc >= 'A' && uc <= 'Z') || Encodings.Unicode.Value.Contains(uc.ToString()) || TypingMethods.List[Global.KeySettings.TypingMethod].Contains(uc));
		}
        private void MyKeyUp(object sender, KeyEventArgs e)
        {
        	//if(Global.KeySettings.EnabledLogView) txtKeyUp.Text = e.KeyData.ToString();
            if (Global.KeySettings.UseAltZ && e.KeyCode == Global.KeySettings.AltZKey && !control && !shift && alt)
                SwitchMode();
        	bool CtrlShift = false;
            switch(e.KeyData)
        	{
        		case Keys.LControlKey: case Keys.RControlKey: control = false; CtrlShift = shift && !another; break;
        		case Keys.LShiftKey: case Keys.RShiftKey: shift = false; CtrlShift = control && !another; break;
        		case Keys.LMenu: case Keys.RMenu: alt = false; break;
        	}
            if (!Global.KeySettings.UseAltZ && CtrlShift)
            {
                SwitchMode();
                control = shift = alt = another = false;
            }
            if (!control && !shift && !alt)
                another = false;
        }
		
        private void SendBack(int length)
        {
        	if(Global.KeySettings.UseVnInAutoComplete)
        	{
        		sendUnicode("`");
        		sendAnsi(Keys.Back);
        	}
        	for(int i = 0; i < length; i++) sendAnsi(Keys.Back);
        }
        
        private string FromUni(string sText)
        {
        	return Encodings.List[Global.KeySettings.Encoding] == Encodings.Unicode ? sText : Encodings.ConvertFromUnicode(sText, Encodings.List[Global.KeySettings.Encoding].Value);
        }
        
        private string ToUni(string sText)
        {
        	return Encodings.List[Global.KeySettings.Encoding] == Encodings.Unicode ? sText : Encodings.Convert(sText, Encodings.List[Global.KeySettings.Encoding].Value, Encodings.Unicode.Value);
        }
        
        private void SendText(string sText, bool isConvert)
        {
        	if(string.IsNullOrEmpty(sText)) return;
        	if(isConvert)
        	{
	        	string str = FromUni(sText);
	        	sendUnicode(str);
        	}
        	else sendUnicode(sText);
        }
        private void SwitchMode()
        {
            trayIcon.Icon = IsVNMode ? Resources.E : Resources.V;
            IsVNMode = !IsVNMode;
        }
//        private void XuatTiengViet(string s, string s1, bool autocomplete)
//        {
//            if (s != s1)
//            {
//                int xuat = 0;
//                int Index = 0;
//                while (Index < s.Length)
//                {
//                    if ((Index >= s1.Length) || (s[Index] != s1[Index]))
//                    {
//                        break;
//                    }
//                    xuat++;
//                    Index++;
//                }
//                if ((s.Length == (s1.Length - 1)) && (!string.IsNullOrEmpty(gotat)))
//                {
//                    gotat = gotat.Remove(gotat.Length - 1);
//                }
//                if (!Global.KeySettings.UseSendKey)
//                {
//                    if (autocomplete && Global.KeySettings.UseVnInAutoComplete)
//                    {
//                        controlV = true;
//                        keybd_event(0xc0, 0, 0, UIntPtr.Zero);
//                        keybd_event(0xc0, 0, 2, UIntPtr.Zero);
//                        Index = 0;
//                        while (Index < ((s1.Length - xuat) + 1))
//                        {
//                            controlV = true;
//                            keybd_event(8, 0, 0, UIntPtr.Zero);
//                            keybd_event(8, 0, 2, UIntPtr.Zero);
//                            Index++;
//                        }
//                    }
//                    else
//                    {
//                        Index = 0;
//                        while (Index < (s1.Length - xuat))
//                        {
//                            controlV = true;
//                            keybd_event(8, 0, 0, UIntPtr.Zero);
//                            keybd_event(8, 0, 2, UIntPtr.Zero);
//                            Index++;
//                        }
//                    }
//                    if (xuat != s.Length)
//                    {
//                        gotat = null;
//                        SetClipboardAPI(s.Substring(xuat, s.Length - xuat));
//                        if (shiftR)
//                        {
//                            keybd_event(0x10, 0, 0, UIntPtr.Zero);
//                            keybd_event(0x2d, 0, 1, UIntPtr.Zero);
//                            keybd_event(0x2d, 0, 2, UIntPtr.Zero);
//                            keybd_event(0x10, 0, 2, UIntPtr.Zero);
//                        }
//                        else if (shiftL)
//                        {
//                            controlV = true;
//                            keybd_event(160, 0, 2, UIntPtr.Zero);
//                            keybd_event(0x11, 0, 0, UIntPtr.Zero);
//                            keybd_event(0x56, 0, 0, UIntPtr.Zero);
//                            keybd_event(0x56, 0, 2, UIntPtr.Zero);
//                            keybd_event(0x11, 0, 2, UIntPtr.Zero);
//                            keybd_event(160, 0, 0, UIntPtr.Zero);
//                        }
//                        else
//                        {
//                            controlV = true;
//                            keybd_event(0x11, 0, 0, UIntPtr.Zero);
//                            keybd_event(0x56, 0, 0, UIntPtr.Zero);
//                            keybd_event(0x56, 0, 2, UIntPtr.Zero);
//                            keybd_event(0x11, 0, 2, UIntPtr.Zero);
//                        }
//                    }
//                }
//                else
//                {
//                    if (autocomplete && Global.KeySettings.UseVnInAutoComplete)
//                    {
//                        sendUnicode("`");
//                        Index = 0;
//                        while (Index < ((s1.Length - xuat) + 1))
//                        {
//                            controlV = true;
//                            sendAnsi(Keys.Back);
//                            Index++;
//                        }
//                    }
//                    else
//                    {
//                        Index = 0;
//                        while (Index < (s1.Length - xuat))
//                        {
//                            controlV = true;
//                            sendAnsi(Keys.Back);
//                            Index++;
//                        }
//                    }
//                    if (xuat != s.Length)
//                    {
//                        gotat = null;
//                        sendUnicode(s.Substring(xuat));
//                    }
//                }
//            }
//        }
    }
}